home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / std / c++ / 189 < prev    next >
Encoding:
Internet Message Format  |  1996-08-06  |  6.2 KB

  1. Path: engnews1.Eng.Sun.COM!taumet!clamage
  2. From: John Max Skaller <maxtal@suphys.physics.su.oz.au>
  3. Newsgroups: comp.std.c++
  4. Subject: Re: Guarantees concerning references/pointers into string
  5. Date: 28 Jan 1996 23:24:34 GMT
  6. Organization: MAXTAL
  7. Approved: clamage@eng.sun.com (comp.std.c++)
  8. Message-ID: <310BF7E7.4DDE@suphys.physics.su.oz.au>
  9. References: <KANZE.96Jan25184235@gabi.gabi-soft.fr>
  10. NNTP-Posting-Host: 129.146.88.126
  11. Mime-Version: 1.0
  12. Content-Type: text/plain; charset=us-ascii
  13. Content-Transfer-Encoding: 7bit
  14. X-Nntp-Posting-Host: slsyd4p22.ozemail.com.au
  15. X-Mailer: Mozilla 2.0b6a (WinNT; I)
  16. Content-Length: 5440
  17. Originator: clamage@taumet
  18.  
  19. J. Kanze wrote:
  20.  
  21. >         a = "A lot of junk" ;
  22. >         a.reserve( 100 ) ;
  23. >         char*               p1 = &a[ 1 ] ;
  24. >         //  b = a ;
  25. >         a.insert( 6 , "---" ) ;
  26. >         char*               p2 = &a[ 1 ] ;
  27. >         cout << "Reserve test: " << (p1 == p2 ? "Passed" : "Failed") << endl ;
  28. > As I interpret the standard, the above is required to work.
  29.  
  30.     I agree. It should work.
  31.  
  32.  
  33. > The presense of
  34. > `reserve' makes copy on write anything but trivial to implement
  35. > correctly.  (The exact case above is actually easy to avoid, and I'm
  36. > surprised that g++ has the error.  But try uncommenting the assignment
  37. > in the above code, and it becomes considerably more difficult to avoid
  38. > the problem.)
  39.  
  40.     I do NOT understand. There is a problem with
  41. copy on write implementations, but it has nothing to do with
  42. reserve(). Rather, the problem occurs because of aliasing:
  43.  
  44.     void f(string &x, string const &y) {
  45.         char &ch = y[0];
  46.         x = "fred";
  47.     }
  48.  
  49. Is "ch" assured? Nope:
  50.  
  51.     string s = "Hi";
  52.     f(s,s);
  53.  
  54.  
  55. Consider now:
  56.  
  57.     void f(string &x, string const &y) {
  58.         char &ch = y[0];
  59.         cout << x[0] << ch;
  60.     }
  61.  
  62. Here, ch might _still_ be invalidated even though there
  63. is no write operation -- merely binding a non-const
  64. lvalue into the string _potentially_ allows writing,
  65. and the string class has no choice but to do the copy
  66. immediately. C++ overloads on the constness of the object
  67. and not whether the context is an lvalue or rvalue context.
  68.  
  69. > One further question occurs: when may reallocation (and the resulting
  70. > invalidation of the pointers) occur when reserve has not been called?
  71. > For example, is the following guaranteed to work as expected:
  72. >     string              s ;
  73. >     size_t              i , j ;
  74. >     assert( i < s.size() , j < s.size() ) ;
  75. >     s[ i ] = s[ j ] ;
  76. > I would like for the last statement to be well defined, but according to
  77. > my reading of the standard, it isn't.  Reallocation is allowed in the
  78. > non-const version of operator[] (and must be, if copy on write is to be
  79. > a legal implementation).  
  80.  
  81.     "must be" doesn't follow -- indexing _could_ return
  82. a proxy object rather than a reference, couldn't it?
  83.  
  84. > This operator is called twice in the
  85. > expression, and the compiler could very easily (and legally) generate
  86. > both calls before using either of the results.  But if the second call
  87. > reallocates, the reference returned by the first call is invalidated.
  88. > (I cannot actually conceive of an implementation in which the second
  89. > call reallocates, but I cannot find anything in the draft to guarantee
  90. > that it won't.)
  91.  
  92. A naive COW implementation in which the "first" evaluated index operator 
  93. is the RHS above and for which a const alias is used will 
  94. invoke the CONST indexing operator, while evaluating 
  95. the LHS invokes the NONCONST indexing operator and triggers 
  96. reallocation. For example:
  97.  
  98.     string s = "Hello";
  99.     string const &cs = s;
  100.     s[0] = cs[0];
  101.  
  102. is almost certain to fail in a naive COW implementation
  103. if the RHS indexing happens to return a lvalue instead 
  104. of an rvalue. 
  105.  
  106. Here's another case:
  107.  
  108.     s.insert(const_iterator, "x");
  109.  
  110. [No, there's nothing wrong with inserting at a const iterator.
  111. It is the string object before the dot (.) that must be
  112. non-const to support insertion, NOT the iterator, which merely
  113. marks the place where the insertion is to occur.]
  114. But calling the "insert" method might trigger a reallocation.
  115.  
  116. I would not be surprised at an implemention
  117. which split the representation when ANY iterator 
  118. was got from the string -- const or not. The same
  119. fix can be applied to indexing (requiring a mutable
  120. pointer inside the string object).
  121.  
  122. Is there a rule for writing COW that makes it work???
  123.  
  124. Yes. IF any method returns something that
  125. binds directly to the representation, it must
  126. be split BEFORE the binding is done.
  127.  
  128. For example, if the indexing operator uses
  129. a suitable proxy, there's no problem.
  130. Similarly, if the iterators are pairs:
  131.  
  132.     (string*, index)
  133.  
  134. there's no problem. 
  135.  
  136. My current string class MTLstring does the latter AND is a naive 
  137. (non-COW) implementation AND allows accesses
  138. "off the end" -- it is highly robust, and VERY hard to break 
  139. without doing "obvious" things (like deleting the string).
  140. It permits you to insert or erase in the string
  141. and will NOT invalidate any iterators. In fact,
  142. my iterators CANNOT be invalidated except by deleting
  143. the string. They may, of course, magically point to
  144. a new character after an insertion. [In fact,
  145. my iterators can be anchored at EITHER end of the
  146. string, so a "end()-1" iterator is NOT moved
  147. by an insertion at end()-2, because it's anchored
  148. to the RHS end of the string, not the LHS end.]
  149.  
  150. The price is inefficiency: read/write can
  151. be made very efficient by grabbing a pointer
  152. to the raw array, but duplicate copying
  153. make the class unsuitable for som applications.
  154.  
  155. But I'm just not interested in chasing the kind of 
  156. horrible problems that fragile implementations have, in a class
  157. I personally conceive as a formatting
  158. and message passing utility.
  159.  
  160. A reasonable compromise for a COW implementation
  161. to make users of the indexing operators
  162. and STL iterators pay for using non-OO syntax:
  163.  
  164.     s.put(index, chr)
  165.  
  166. does not suffer from these problems, for example.
  167.  
  168. -- 
  169. John Max Skaller               voice: 61-2-566-2189
  170. 81 Glebe Point Rd              fax:   61-2-660-0850
  171. GLEBE NSW 2037                 web: http://www.maxtal.com.au/~skaller/
  172. AUSTRALIA                      email: skaller@maxtal.com.au
  173.  
  174. [ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  175.   Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  176.   is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
  177.  
  178.